#!/usr/bin/env ruby
# frozen_string_literal: true

# genprofiles: generate a lookup table of profiles names -> syscall lists

require "yaml"

# PLATFORM = ARGV.shift || `uname -s`.chomp!.downcase!
PLATFORM = "linux"

abort "Barf: Unknown platform: #{PLATFORM}" unless %w[linux freebsd].include? PLATFORM

PROFILE_DESC_FILE = File.expand_path "./profiles.yml", __dir__
SYSCALL_SPECS_DIR = File.expand_path File.join("../module/codegen/", PLATFORM), __dir__
SYSCALL_SPECS = Dir[File.join(SYSCALL_SPECS_DIR, "*.yml")]

SYSCALLS = SYSCALL_SPECS.map do |path|
  spec = YAML.safe_load File.read(path)
  [File.basename(path, ".yml"), spec]
end.to_h

PROFILE_DESCS = YAML.safe_load File.read(PROFILE_DESC_FILE)
PROFILE_DESCS.default = Hash.new "<no description for this profile; please contribute one>"

PROFILES = Hash.new { |h, k| h[k] = [] }

SYSCALLS.each do |call, spec|
  # __NR_<name> constant always takes precedence, since
  # we extract our lookup table from those constants in gentable.
  sys_name = spec["nr"] || call
  spec["profiles"]&.each do |profile|
    PROFILES[profile] << sys_name
  end
  PROFILES["all"] << sys_name
end

OUTPUT_NAME = File.expand_path "profiles.gen.c", __dir__

def hai(msg)
  STDERR.puts "[genprofiles] #{msg}"
end

hai "building lookup table with #{PROFILES.size} entries"

File.open(OUTPUT_NAME, "w") do |file|
  file.puts <<~PREAMBLE
    /* WARNING!
     * This file was generated by KRF's genprofiles.
     * Do not edit it by hand.
     */

    #include <stdlib.h>

    #include "krfctl.h"
  PREAMBLE

  file.puts "fault_profile_t fault_profile_table[] = {"

  PROFILES.each do |name, syscalls|
    desc = PROFILE_DESCS[name]
    sys_struct = syscalls.map { |s| "\"#{s}\"" }.join ", "
    file.puts %({ "#{name}", "#{desc}", { #{sys_struct}, NULL } },)
  end

  file.puts "{ NULL, NULL, { NULL } },"
  file.puts "};"
end
